package org.smarthings.things.management.rest.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smarthings.things.management.ThingProperty;
import org.smarthings.things.management.metadata.ThingActionArgumentMetadata;
import org.smarthings.things.management.metadata.ThingPropertyMetadata;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class DOMElementMarshaller {

	private final static Logger logger = LoggerFactory.getLogger(DOMElementMarshaller.class);

	public static Element marshal(String elementName, Object elementValue) {
		Element element = null;
		if (elementValue == null) {
			return null;
		}
		try {

			QName rootElement = new QName(elementName);
			Class elementValueType = elementValue.getClass();
			JAXBElement jaxbElement = new JAXBElement(rootElement, elementValueType, elementValue);
			Document document = getDocumentBuilder().newDocument();
			JAXBContext.newInstance(elementValueType).createMarshaller()
					.marshal(jaxbElement, document);
			element = document.getDocumentElement();
		} catch (JAXBException e) {
			e.printStackTrace();
			logger.error("Error while marshalling value " + elementValue, e);
		}
		return element;
	}

	public static Element marshalThingPropertyValue(ThingProperty property) {
		return marshal("value", property.getValue());
	}

	public static List<Element> marshalThingActionArgumentMetaData(
			ThingActionArgumentMetadata metadata) {
		List<Element> elements = null;
		try {
			elements = new ArrayList<Element>(2);
			elements.add(marshal("description", metadata.getDescription()));
			elements.add(marshal("type", metadata.getType()));
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("Error while marshalling action argument metadata " + metadata, e);
		}
		return elements;
	}

	public static List<Element> marshalThingPropertyMetaData(ThingPropertyMetadata metadata) {
		List<Element> elements = null;
		try {
			elements = new ArrayList<Element>(4);
			elements.add(marshal("description", metadata.getDesctiption()));
			elements.add(marshal("type", metadata.getType()));
			elements.add(marshal("unit", metadata.getUnit()));
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("Error while marshalling property metadata " + metadata, e);
		}
		return elements;
	}

	public static Map<String, String> marshalThingActionArguments(Map<String, Object> arguments) {
		Map<String, String> result = null;
		if (arguments != null && arguments.size() > 0) {
			result = new HashMap<String, String>(arguments.size());
			for (Map.Entry<String, Object> argument : arguments.entrySet()) {
				result.put(argument.getKey(), String.valueOf(argument.getValue()));
			}
		}
		return result;
	}

	private static DocumentBuilder builder;

	private static DocumentBuilder getDocumentBuilder() {
		if (builder == null) {
			try {
				builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				//
			}
		}
		return builder;
	}

}
